

import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.net.InetSocketAddress;

public class CNIOServerDemo2 {
    public static void main(String[] args) throws IOException{
        Selector selc = Selector.open();  //打开一个选择器
        ServerSocketChannel ssc = ServerSocketChannel.open();  //打开一个socket通道
        ssc.configureBlocking(false);    //指定ssc这个通道为非阻塞模式
        ssc.socket().bind(new InetSocketAddress(9999));
        //注册代码
        ssc.register(selc,SelectionKey.OP_ACCEPT);    //  后面那个是ops，就是选项，OP_ACCEPT OP_CONNECT OP_READ OP_WRITE
        //执行selector操作，相当于大喊一声,注册在我身上的SelectionKey们，哪一个sk对应的通道已经为当初注册的事件就绪了
        while(true){
            int selcCont = selc.select();
            if(selcCont >0){
                System.out.println(selc.select());
                //如果sk大于0说明，已经有人就绪了
                Set<SelectionKey> set= selc.selectedKeys();  //这个得先大喊一声 才能做这个操作，set是一个集合，里面是就绪的sk
                Iterator<SelectionKey> it = set.iterator();	//--遍历处理sk对应的通道事件,这里是做一个迭代器
                while(it.hasNext()){
                    SelectionKey sk = it.next();    //取出每一个通道对象
                    if(sk.isAcceptable()){    //判断是什么操作.其实可以写为sk.interestOps() == SelectionKey.OP_ACCEPT,自动返回布尔类型
                        ServerSocketChannel sscx = (ServerSocketChannel)sk.channel();  //拿到sk的通道
                        SocketChannel sc = sscx.accept();     //创建accept对象
                        sc.configureBlocking(false);    //设置非阻塞模式
                        sc.register(selc, SelectionKey.OP_READ|SelectionKey.OP_WRITE);  //读数据
                    }else if(sk.isConnectable()){

                    }else if(sk.isReadable()){
                        //读取客户端发送的数据
                        SocketChannel sc = (SocketChannel)sk.channel();

                        ByteBuffer temp = ByteBuffer.allocate(1);
                        String head = "";
                        while (!head.endsWith("\r\n")){     //添加数据包分割符
                            sc.read(temp);
                            head += new String(temp.array());
                            temp.clear();
                        }
                        int len = Integer.parseInt(head.substring(0,head.length()-2));
                        ByteBuffer buf = ByteBuffer.allocate(len);

                        while(buf.hasRemaining()){
                            sc.read(buf);       //把数据填充到缓冲区
                        }

//						sc.read(buf);
                        String msg = new String(buf.array(),"utf-8");
                        System.out.println("服务器收到了"+sc.socket().getInetAddress()+"发来的："+msg);

                        sc.register(selc,SelectionKey.OP_WRITE);     //注册WRITE的请求，为了给客户端返回消息，下次循环的时候就会进入isWriteble里面


                    }else if(sk.isWritable()){
                        System.out.println("开始写");
                        SocketChannel scx = (SocketChannel) sk.channel();//获取通道
                        StringBuffer sb = new StringBuffer();
                        String str = "你好 我是服务器";
                        String sendStr = str.getBytes().length+"\r\n"+str;

                        ByteBuffer buf = ByteBuffer.wrap(sendStr.getBytes());  //发送数据
                        while(buf.hasRemaining()){
                            scx.write(buf);
                        }
                        scx.register(selc,sk.interestOps() & ~SelectionKey.OP_WRITE); //取消write注册 ~是取反 &是与
                    }else{
                        throw new RuntimeException("selector操作方式出错");
                    }
                    it.remove();   //清楚已处理过后的键，不删除会重复处理
                }
            }
        }


    }


}